package com.symaster.common.geom.entity;

import com.symaster.common.geom.util.ArithUtil;

import java.util.Map;

import java.util.*;

/**
 * 位图映射
 *
 * @author yinmiao
 * @date 2021-08-11 10:31
 */
public class BitMap<T> implements Cloneable {

    private final Map<T, Set<PointInt>> indexmap;
    private final Map<PointInt, List<T>> bitmap;
    private final double elementWidth;
    private final double elementHeight;
    private final int rows;
    private final int cols;

    /**
     * 初始化位图映射
     *
     * @param width           总宽度
     * @param height          总高度
     * @param horizontalSplit 水平分割
     * @param verticalSplit   垂直分割
     */
    public BitMap(int width, int height, int horizontalSplit, int verticalSplit) {
        if (horizontalSplit <= 0) {
            throw new IllegalArgumentException("水平分割(widthSplit)不应该小于1");
        }
        if (verticalSplit <= 0) {
            throw new IllegalArgumentException("垂直分割(heightSplit)不应该小于1");
        }
        bitmap = new HashMap<>();
        indexmap = new HashMap<>();
        this.elementWidth = ArithUtil.div(width, horizontalSplit);
        this.elementHeight = ArithUtil.div(height, verticalSplit);
        this.rows = verticalSplit + 1;
        this.cols = horizontalSplit + 1;

        for (int y = 0; y < rows; y++) {
            for (int x = 0; x < cols; x++) {
                bitmap.put(new PointInt(x, y), new LinkedList<>());
            }
        }
    }

    public void add(Polygon polygon, T value) {

    }

    public ElementPathIterator getElementPathIterator() {
        return new ElementPathIterator();
    }

    public LineIterator getLineIterator() {
        return new LineIterator();
    }

    /**
     * 获取指定元素上的数据
     */
    private List<T> _get(int x, int y) {
        return bitmap.get(new PointInt(x, y));
    }

    /**
     * 获取指定区域上的数据
     */
    private List<T> _get(int x, int y, int width, int height) {
        List<T> result = new LinkedList<>();
        for (int ix = x; ix < width; ix++) {
            for (int iy = y; iy < height; iy++) {
                List<T> ts = bitmap.get(new PointInt(x, y));
                if (ts == null || ts.size() == 0) {
                    continue;
                }
                result.addAll(ts);
            }
        }
        return result;
    }

    /**
     * 返回某个内容所占用元素
     */
    private Set<PointInt> _get(T value) {
        return indexmap.get(value);
    }

    /**
     * 在指定元素上添加数据
     */
    private void _put(int x, int y, T value) {
        bitmap.get(new PointInt(x, y)).add(value);
        Set<PointInt> pointInts1 = indexmap.get(value);
        pointInts1 = pointInts1 == null ? new HashSet<>() : pointInts1;
        pointInts1.add(new PointInt(x, y));
        indexmap.put(value, pointInts1);
    }

    /**
     * 在指定区域上添加数据
     */
    private void _put(int x, int y, int width, int height, T value) {
        for (int ix = x; ix < width; ix++) {
            for (int iy = y; iy < height; iy++) {
                PointInt pointInt = new PointInt(x, y);
                List<T> ts = bitmap.get(pointInt);
                if (ts == null) {
                    continue;
                }
                ts.add(value);
                Set<PointInt> pointInts1 = indexmap.get(value);
                pointInts1 = pointInts1 == null ? new HashSet<>() : pointInts1;
                pointInts1.add(new PointInt(x, y));
                indexmap.put(value, pointInts1);
            }
        }
    }

    public int getRows() {
        return rows;
    }

    public int getCols() {
        return cols;
    }

    public double getElementWidth() {
        return elementWidth;
    }

    public double getElementHeight() {
        return elementHeight;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        BitMap<?> bitMap = (BitMap<?>) o;
        return Objects.equals(bitmap, bitMap.bitmap);
    }

    @Override
    public int hashCode() {
        return Objects.hash(bitmap);
    }

    @Override
    public String toString() {
        return "BitMap{" +
                "bitmap=" + bitmap +
                '}';
    }

    @Override
    public BitMap clone() {
        BitMap clone = null;
        try {
            clone = (BitMap) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return clone;
    }

    /**
     * 元素迭代器
     */
    class ElementPathIterator {

        private PointInt index;

        public List<T> get() {
            return _get(index.getX(), index.getY());
        }

        public boolean isDone() {
            return index.getX() * index.getY() >= rows * cols;
        }

        public void next() {
            if (index.getX() >= cols) {
                index.setX(0);
                index.setY(index.getY() + 1);
                return;
            }
            index.setX(index.getX() + 1);
        }
    }

    /**
     * 逐行迭代器
     */
    class LineIterator {

        private Integer line;

        public List<T> get() {
            return _get(0, line, cols, 1);
        }

        public boolean isDone() {
            return line >= rows;
        }

        public void next() {
            line++;
        }
    }
}
